using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace BrainWare
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class BrainWareGame : Microsoft.Xna.Framework.Game
    {
        /// <summary>
        /// A cache of content used by the game
        /// </summary>
        public new static ContentManager Content;

        /// <summary>
        /// The game settings from settings.xml
        /// </summary>
        public static Settings Settings = new Settings();

        /// <summary>
        /// The current game state
        /// </summary>
        public static GameState GameState = GameState.Started;

        /// <summary>
        /// The storage device that the game is saving high-scores to.
        /// </summary>
        public static StorageDevice StorageDevice = null;

        /// <summary>
        /// The new game state
        /// </summary>
        public static GameState NextGameState = GameState.None;

        public static int Score; //= 0;

        public static List<int> HighScores;

        private GraphicsDeviceManager graphics;
        private GameScreen mainGame;
        private TitleScreen splashScreen;
        private InputHelper inputHelper;
        private int previousWindowWidth = 1280;
        private int previousWindowHeight = 720;
        private KeyboardState keyState;
        private bool justWentFullScreen;

        public BrainWareGame()
        {
#if !XBOX360
            //Uncomment this line to force a save of the default settings file. Useful 
            //when you had added things to settings.cs
            //project Settings.Save("settings.xml");
#endif
            Settings = Settings.Load("settings.xml");

            //Create the content pipeline manager.
            base.Content.RootDirectory = "Content";
            BrainWareGame.Content = base.Content;

            //Set up the device to be HD res. The RelativeSpriteBatch will handle 
            //resizing for us
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;

            Window.AllowUserResizing = true;

            mainGame = new GameScreen(this, "Textures/title_screen", SoundEntry.Giggle);
            mainGame.Enabled = false;
            mainGame.Visible = false;
            this.Components.Add(mainGame);

            splashScreen =
                new TitleScreen(this, "Textures/title_screen", SoundEntry.Giggle);
            splashScreen.Enabled = true;
            splashScreen.Visible = true;
            this.Components.Add(splashScreen);

            inputHelper = new InputHelper(this);
            inputHelper.UpdateOrder = int.MinValue;
            this.Components.Add(inputHelper);

            this.Components.Add(new GamerServicesComponent(this));
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            Sound.Initialize();

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)Services.GetService(typeof(IGraphicsDeviceService));

            //Correct settings for alpha blending in 3d game mode
            graphicsService.GraphicsDevice.RenderState.AlphaSourceBlend =
                Blend.SourceAlpha;

            graphicsService.GraphicsDevice.RenderState.DestinationBlend =
                Blend.InverseSourceAlpha;

            //Ask static helper objects to reload too
            Font.LoadContent();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            //Handle FullScreen
            keyState = Keyboard.GetState();

            // Allows the default game to exit on Xbox 360 and Windows
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                AltComboPressed(keyState, Keys.F4) ||
                keyState.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

            if ((keyState.IsKeyDown(Keys.RightAlt) || keyState.IsKeyDown(Keys.LeftAlt))
                && keyState.IsKeyDown(Keys.Enter) && !justWentFullScreen)
            {
                ToggleFullScreen();
                justWentFullScreen = true;
            }
            if (keyState.IsKeyUp(Keys.Enter))
            {
                justWentFullScreen = false;
            }

            if (InputHelper.GamePads[PlayerIndex.One].StartPressed)
            {
                NextGameState = GameState.Started;
            }

            if (NextGameState != GameState.None)
            {
                ChangeGameState();
            }
        }


        private void ToggleFullScreen()
        {
            PresentationParameters presentation =
                graphics.GraphicsDevice.PresentationParameters;

            if (presentation.IsFullScreen)
            {   // going windowed
                graphics.PreferredBackBufferWidth = previousWindowWidth;
                graphics.PreferredBackBufferHeight = previousWindowHeight;
            }
            else
            {
                previousWindowWidth = graphics.GraphicsDevice.Viewport.Width;
                previousWindowWidth = graphics.GraphicsDevice.Viewport.Width;

                // going fullscreen, use desktop resolution to minimize display mode 
                // changes this also has the nice effect of working around some displays
                // that lie about supporting 1280x720
                GraphicsAdapter adapter =
                    graphics.GraphicsDevice.CreationParameters.Adapter;

                graphics.PreferredBackBufferWidth = adapter.CurrentDisplayMode.Width;
                graphics.PreferredBackBufferHeight = adapter.CurrentDisplayMode.Height;
            }

            graphics.ToggleFullScreen();
        }


        private void ChangeGameState()
        {
            //Brainiac only has 3 game states - the splash screen and the game screen
            //in 2d and 3d Since they are both game components of type screen just 
            //making the right one visible will cause the correct background to be shown
            //and the right music to be played
            if ((GameState == GameState.Started) && (NextGameState == GameState.Play2D))
            {
                Score = 0;
                splashScreen.Enabled = false;
                splashScreen.Visible = false;
                mainGame.Enabled = true;
                mainGame.Visible = true;
                //Start a new game - reset score and board etc
                mainGame.NewGame();
                GameState = NextGameState;
            }
            else if (NextGameState == GameState.Started)
            {
                splashScreen.Enabled = true;
                splashScreen.Visible = true;
                mainGame.Enabled = false;
                mainGame.Visible = false;

                GameState = NextGameState;

            }
        }


        /// <summary>
        /// Checks whether an alt+key combo is pressed.
        /// </summary>
        private static bool AltComboPressed(KeyboardState state, Keys key)
        {
            return state.IsKeyDown(key) &&
                   (state.IsKeyDown(Keys.LeftAlt) ||
                    state.IsKeyDown(Keys.RightAlt));
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }
    }


    /// <summary>
    /// This enum is for the state transitions.
    /// </summary>
    public enum GameState
    {
        /// <summary>
        /// Default value - means no state is set
        /// </summary>
        None,

        /// <summary>
        /// Nothing visible, game has just been run and nothing is initialized
        /// </summary>
        Started,

        /// <summary>
        /// Logo Screen is being displayed
        /// </summary>
        LogoSplash,

        /// <summary>
        /// Currently playing the 2d version
        /// </summary>
        Play2D,

    }
}
